package com.leyou.item.service.impl;


import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.leyou.common.constants.MQConstants;
import com.leyou.common.dto.*;
import com.leyou.common.exception.LyException;
import com.leyou.common.utils.JsonUtils;
import com.leyou.item.entity.*;
import com.leyou.item.mapper.SpuMapper;
import com.leyou.item.service.*;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.leyou.common.constants.MQConstants.ExchangeConstants.ITEM_EXCHANGE_NAME;
import static com.leyou.common.constants.MQConstants.RoutingKeyConstants.ITEM_DOWN_KEY;
import static com.leyou.common.constants.MQConstants.RoutingKeyConstants.ITEM_UP_KEY;


/**
 * @author
 */
@Service
public class SpuServiceImpl extends ServiceImpl<SpuMapper, Spu> implements SpuService {

    @Autowired
    private BrandService brandService;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private SkuService skuService;

    @Autowired
    private SpuDetailService spuDetailService;

    @Autowired
    private SpecParamService specParamService;

    @Autowired
    private AmqpTemplate amqpTemplate;

    @Override
    @Transactional
    public void updateSaleable(Long id, Boolean saleable) {
        Spu spu = new Spu();
        spu.setId(id);
        spu.setSaleable(saleable);
        boolean success = updateById(spu);
        if (!success) {
            throw new LyException(500, "上下架更新失败");
        }
        //更新sku表
        success = skuService.update().eq("spu_id", id).set("saleable", saleable).update();
        if (!success) {
            throw new LyException(500, "上下架更新失败");
        }

        //发送MQ消息
        String rountingKey =saleable?ITEM_UP_KEY:ITEM_DOWN_KEY;
        amqpTemplate.convertAndSend(ITEM_EXCHANGE_NAME,rountingKey,id);


    }

    @Override
    public PageDTO<SpuDTO> queryByPage(Long brandId, Long categoryId, Long id, Integer page, Integer rows, Boolean saleable) {

        //1.分页代码健壮性
        if (page < 0 || rows < 0) {
            throw new LyException(400, "分页参数异常");
        }
        //2. 分页查询
        //SELECT * FROM  tb_spu s
        Page<Spu> result = query()
                //WHERE s.brand_id =18374 AND
                .eq(brandId != null, "brand_id", brandId)
                //s.cid3 =76 AND
                .eq(categoryId != null, "cid3", categoryId)
                .eq(id != null, "id", id)
                //s.saleable = 1
                .eq(saleable != null, "saleable", saleable)
                //LIMIT 0,5;
                .page(new Page<>(page, rows));
        //3. 转po到dto
        List<SpuDTO> spuDTOList = SpuDTO.convertEntityList(result.getRecords());
        //4. 获取 brandName 和 categoryName
        for (SpuDTO spuDTO : spuDTOList) {
            getBrandNameAndCategoryName(spuDTO);

        }

        //5. 返回分页结果
        return new PageDTO<>(result.getTotal(), result.getPages(), spuDTOList);
    }

    @Transactional
    @Override
    public void saveGoods(SpuDTO spuDTO) {
        //更改3张表
        //1.spu
        //1.1 DTO转po
        Spu spu = spuDTO.toEntity(Spu.class);
        //1.2 商品设置为默认下架
        spu.setSaleable(false);
        //1.3 插入数据
        boolean success = save(spu);
        if (!success) {
            throw new LyException(500, "spu数据保存失败");
        }
        //1.4 id回显
        Long spuId = spu.getId();

        //2.spuDetail
        //1.1 DTO转po
        SpuDetail spuDetail = spuDTO.getSpuDetail().toEntity(SpuDetail.class);
        //1.2 spu和spuDetail的id值一样
        spuDetail.setSpuId(spuId);
        //1.3 插入数据
        success = spuDetailService.save(spuDetail);
        if (!success) {
            throw new LyException(500, "spuDetail数据保存失败");
        }
        //3.sku
        //3.1获取skudtolist
        List<SkuDTO> skuDtos = spuDTO.getSkus();
        //3.2 stream流 获取skulist
        List<Sku> skuList = skuDtos.stream().map(skuDTO -> {
            Sku sku = skuDTO.toEntity(Sku.class);
            sku.setSpuId(spuId);
            sku.setSaleable(false);
            sku.setSold(0L);
            return sku;
        }).collect(Collectors.toList());
        //3.批处理插入数据库
        skuService.saveBatch(skuList);

    }

    @Transactional
    @Override
    public void updateGoods(SpuDTO spuDTO) {
        boolean success;
        //1.更改spu
        //1.1 判断spuid是否存在
        if (spuDTO.getId() != null) {
            //1.2 dto转po
            Spu spu = spuDTO.toEntity(Spu.class);
            //1.3禁止修改saleable
            spu.setSaleable(null);
            //1.4 更新数据
            success = updateById(spu);
            if (!success) {
                throw new LyException(500, "商品更新失败");
            }

        }

        //2. 更改spuDetail
        SpuDetailDTO spuDetailDTO = spuDTO.getSpuDetail();
        //2.1 判断
        if (spuDetailDTO != null && spuDetailDTO.getSpuId() != null) {
            //2.2 转dto到po
            SpuDetail spuDetail = spuDetailDTO.toEntity(SpuDetail.class);
            if(spuDetail==null){
                throw new LyException(500, "spuDetail为空!!!");
            }
            //2.3插入数据
            success = spuDetailService.updateById(spuDetail);
            if (!success) {
                throw new LyException(500, "spuDetail商品更新失败!!!");
            }
        }

        //3. 更改sku
        //3.1 获取skuDTOList
        List<SkuDTO> skuDTOList = spuDTO.getSkus();
        //3.2判断
        if (CollectionUtils.isEmpty(skuDTOList)) {
            return;
        }
        //3.3 需要对sku进行增删改
        Map<Boolean, List<Sku>> skuMap = skuDTOList.stream()
                //转dto到po
                .map(skuDTO ->  skuDTO.toEntity(Sku.class))
                //对集合进行分组,判断依据:是否包含saleable, 包含: 删除 不包含: 增或改
                .collect(Collectors.groupingBy(sku -> sku.getSaleable() != null));
        //3.4 获取要删除的sku
        List<Sku> deleteSkuList = skuMap.get(true);
        if(!CollectionUtils.isEmpty(deleteSkuList)){
            //获取要删除的数据的id集合
            List<Long> deleteIdList = deleteSkuList.stream().map(Sku::getId).collect(Collectors.toList());
            //根据id删除数据
            skuService.removeByIds(deleteIdList);

        }

        //3.5 获取要增或者修改的sku
        List<Sku> insertOrUpdateSkuList = skuMap.get(false);
        if(!CollectionUtils.isEmpty(insertOrUpdateSkuList)){
            insertOrUpdateSkuList.forEach(sku -> sku.setSaleable(false));
            //批处理
            skuService.saveOrUpdateBatch(insertOrUpdateSkuList);
        }

    }

    @Override
    public SpuDTO querySpuAndDetailAndSku(Long id) {
        //查询3张表
        //1.查询spu
        //1.1 根据id查询spu
        Spu spu = getById(id);
        //1.2 对结果进行判断
        if (spu == null) {
            throw new LyException(400, "商品id不存在!!!");
        }
        //1.3 转po到dto
        SpuDTO spuDTO = new SpuDTO(spu);


        //2.查询spuDetail
        //2.1 根据id查询 spuDetail
        SpuDetail spuDetail = spuDetailService.getById(id);
        //2.2 判断
        if (spuDetail == null) {
            throw new LyException(400, "商品id不存在!!!");
        }
        //2.3 转po到dto
        SpuDetailDTO spuDetailDTO = new SpuDetailDTO(spuDetail);
        spuDTO.setSpuDetail(spuDetailDTO);

        //3. 查询 sku
        //3.1 根据id查询 sku数据
        List<Sku> skuList = skuService.query().eq("spu_id", id).list();
        //3.2 判断
        if(CollectionUtils.isEmpty(skuList)){
            throw new LyException(400, "商品id不存在!!!");
        }
        //3.3 转po到dto
        List<SkuDTO> skuDTOList = SkuDTO.convertEntityList(skuList);
        //3.4 将Skus封装到spuDto中
        spuDTO.setSkus(skuDTOList);

        //4.查询 brandName 和 categoryName
        getBrandNameAndCategoryName(spuDTO);

        return spuDTO;
    }

    @Override
    public List<SpecParamDTO> querySpuDetailById(Long id, Boolean searching) {
        //1. 查询spu
        Spu spu = getById(id);
        if(spu==null){
            throw new LyException(500,"spuid不存在");
        }
        Long categoryId = spu.getCid3();
        //2. 查询specParam的参数集合
        List<SpecParamDTO> specParamDTOList = specParamService.queryParamList(categoryId, null, searching);
        //3.查询参数的value值
        SpuDetail spuDetail = spuDetailService.getById(id);
        if(spuDetail == null){
            throw new LyException(500,"spuid不存在");
        }
        String specJson = spuDetail.getSpecification();
        Map<Long, Object> specMap = JsonUtils.toMap(specJson, Long.class, Object.class);

        //4. 把value值赋值给specParam
        for (SpecParamDTO specParamDTO : specParamDTOList) {
           Object value = specMap.get(specParamDTO.getId());
            specParamDTO.setValue(value);
        }

        return specParamDTOList;
    }

    private void getBrandNameAndCategoryName(SpuDTO spuDTO) {
        //1. 设置BrandName参数
        //1.1 获取brandId
        Long brandId = spuDTO.getBrandId();
        //1.2 根据id查询brand信息
        Brand brand = brandService.getById(brandId);
        if (brand != null) {
            //1.3 把brandName封装到spuDTO中
            spuDTO.setBrandName(brand.getName());
        }

        //2. 设置CategoryName 参数
        //2.1 获取categoryId
        List<Long> categoryIds = spuDTO.getCategoryIds();
        //2.2 根据id查询category信息
        List<Category> categoryList = categoryService.listByIds(categoryIds);
        if (!CollectionUtils.isEmpty(categoryList)) {
            String name = categoryList.stream().map(Category::getName).collect(Collectors.joining("/"));
            //2.3 把categoryName封装到spuDTO中
            spuDTO.setCategoryName(name);
        }
    }
}